package com.yourenbang.lingyun.transaction.job.handler;

import com.alibaba.fastjson.JSON;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import com.yourenbang.lingyun.constants.AppId;
import com.yourenbang.lingyun.constants.enums.LetterCodeEnum;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.WithDrawStatusEnum;
import com.yourenbang.lingyun.constants.enums.pay.PayFromEnum;
import com.yourenbang.lingyun.core.exception.BizRuntimeException;
import com.yourenbang.lingyun.core.util.BizAssertUtils;
import com.yourenbang.lingyun.core.util.DingdingUtils;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.date.DateFormat;
import com.yourenbang.lingyun.mapper.FundAccountMapper;
import com.yourenbang.lingyun.transaction.config.DingdingConfig;
import com.yourenbang.lingyun.transaction.exception.WichdrawFailException;
import com.yourenbang.lingyun.transaction.exception.WichdrawWaitException;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountWithdrawPaymentMapper;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.FundPayQueryParam;
import com.yourenbang.lingyun.transaction.web.domain.po.FundAccountWithdrawPayment;
import com.yourenbang.lingyun.transaction.web.service.fund.FundService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.WithdrawPayService;
import com.yourenbang.mcenter.api.model.dto.letter.SendLetterDTO;
import com.yourenbang.mcenter.api.service.letter.McenterRpcLetterService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Component
@Slf4j
public class WithdrawQueryHandler {

    @Autowired
    TransactionFundAccountWithdrawPaymentMapper fundAccountWithdrawPaymentMapper;
    @Autowired
    private DingdingConfig dingdingConfig;
    @Autowired
    private WithdrawPayService withdrawPayService;
    @Autowired
    private FundService fundService;
    @Autowired
    private FundAccountMapper fundAccountMapper;
    @Autowired
    private McenterRpcLetterService mcenterRpcLetterService;

    /**
     * 提现查询
     */
    @XxlJob("withdrawQueryHandler")
    public ReturnT<String> withdrawQueryHandler(String param) {

        XxlJobLogger.log("【提现查询】任务开始");

        FundPayQueryParam payQueryParam = JSON.parseObject(param, FundPayQueryParam.class);
        if (Objects.isNull(payQueryParam.getPlatNo())) {
            return ReturnT.FAIL;
        }

        fundPayQueryByPlatNo(payQueryParam);

        return ReturnT.SUCCESS;
    }

    private void fundPayQueryByPlatNo(FundPayQueryParam payQueryParam) {

        List<FundAccountWithdrawPayment> list;
        if (Objects.nonNull(payQueryParam.getBeginDays())) {
            list = fundAccountWithdrawPaymentMapper.findFundIngSetTime(payQueryParam.getPlatNo(), payQueryParam);
        } else if (Objects.nonNull(payQueryParam.getCreateDate())) {
            list = fundAccountWithdrawPaymentMapper.findFundIng(payQueryParam.getPlatNo(), payQueryParam);
        } else {
            list = fundAccountWithdrawPaymentMapper.findFundIng(payQueryParam.getPlatNo(), null);
        }

        if (CollectionUtils.isEmpty(list)) {
            KLog.info("【提现查询】没有提现任务需要处理");
            return;
        }

        KLog.info("【提现查询】需处理任务{}条", list.size());
        for (FundAccountWithdrawPayment fundAccountWithdrawPayment : list) {

            KLog.info("【提现查询】当前处理任务:{}", fundAccountWithdrawPayment);
            fundAccountWithdrawPayment = fundAccountWithdrawPaymentMapper.selectByPrimaryKey(payQueryParam.getPlatNo(), fundAccountWithdrawPayment.getFundAccountWithdrawPaymentId());
            fundAccountWithdrawPayment.setPlatNo(payQueryParam.getPlatNo());

            //调用代付接口成功后,再发起代付状态查询
            if (!WithDrawStatusEnum.WITHDRAW_STATUS_WAIT.getCode().equals(fundAccountWithdrawPayment.getWithdrawStatus())) {
                continue;
            }

            FundAccountWithdrawPayment upWithPay = new FundAccountWithdrawPayment(payQueryParam.getPlatNo());
            LocalDateTime now = LocalDateTime.now();
            upWithPay.setFundAccountWithdrawPaymentId(fundAccountWithdrawPayment.getFundAccountWithdrawPaymentId());

            //查询次数超限
            if (Objects.nonNull(fundAccountWithdrawPayment.getThirdQueryCount())
                    && fundAccountWithdrawPayment.getThirdQueryCount() > 20) {

                DingdingUtils.sendToDingding("【提现查询预警】查询次数超限,请关注,fund:" + fundAccountWithdrawPayment.toJSON(), dingdingConfig.getDingdingWarnToken());
                upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
                upWithPay.setSuccessDate(LocalDateTime.now());
                upWithPay.setRemark(fundAccountWithdrawPayment.getRemark() + ";查询次数超限");
                Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
                BizAssertUtils.assertOne(upPay, "修改提现订单失败");

                continue;
            }

            upWithPay.setThirdQueryTime(now);
            upWithPay.setThirdQueryCount(Objects.isNull(fundAccountWithdrawPayment.getThirdQueryCount()) ? 0 : fundAccountWithdrawPayment.getThirdQueryCount() + 1);

            try {

                // 如果查询失败,抛异常
                //TODO 应明确返回是否成功,增加可读性
                withdrawPayService.withDrawQuery(fundAccountWithdrawPayment);


                upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_SUCCESS.getCode());   //提现成功
                upWithPay.setSuccessDate(LocalDateTime.now());
                upWithPay.setUpdateTime(LocalDateTime.now());

                Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
                BizAssertUtils.assertOne(upPay, "修改提现订单失败");

                //解冻结金额
                fundService.undepositByFundAccountWithdrawPaymentId(upWithPay.getFundAccountWithdrawPaymentId(), payQueryParam.getPlatNo());

                sendMessage(fundAccountWithdrawPayment);

            } catch (WichdrawFailException e) {

                KLog.info("【提现查询】接口明确返回失败, 提现订单:{}", fundAccountWithdrawPayment);

                upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
                upWithPay.setUpdateTime(now);
                upWithPay.setRemark(e.getMessage());
                upWithPay.setErrors(e.getMessage());
                Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
                BizAssertUtils.assertOne(upPay, "修改提现订单失败");

                //归还冻结金额
                fundService.cancelByFundAccountWithdrawPaymentId(upWithPay.getFundAccountWithdrawPaymentId(), payQueryParam.getPlatNo());

                sendFailMessage(fundAccountWithdrawPayment);
            } catch (WichdrawWaitException e) {

                KLog.info("【提现查询】接口返回处理中, 不做处理, 提现订单:{}", fundAccountWithdrawPayment);

            } catch (BizRuntimeException e) {

                KLog.warn("【提现回调】业务异常:{}, 不做处理, 提现订单:{}", e.getErrorMessage(), fundAccountWithdrawPayment);

            } catch (Exception e) {

                KLog.error("【提现查询】未知异常:{}, 不做处理, 提现订单:{}", e.getMessage(), fundAccountWithdrawPayment);

            }
        }

    }


    private void sendFailMessage(FundAccountWithdrawPayment fund) {
        SendLetterDTO sendLetterDTO = new SendLetterDTO();
        sendLetterDTO.setPlatNo(fund.getPlatNo());
        sendLetterDTO.setUserBaseId(fundAccountMapper.selectByPrimaryKey(fund.getFundAccountId()).getUserBaseId());
        if (fund.getWithdrawType().equals(PayFromEnum.yxy_withdraw_mer.getCode())) {
            sendLetterDTO.setAppId(AppId.YXY_MER);
//        } else if (fund.getWithdrawType().equals(PayFromEnum.withdraw_mer.getCode())) {
//            sendLetterDTO.setAppId(AppId.KLKS_PRO);
        } else {
            if (PlatNoEnums.YXY.isEquals(fund.getPlatNo())) {
                sendLetterDTO.setAppId(AppId.YXY);
            } else {
                sendLetterDTO.setAppId(AppId.KLLC);
            }
        }
        Map<String, String> map = new HashMap<>();
        map.put("year", DateFormat.YEAR.format(fund.getCreateTime()));
        map.put("month", DateFormat.MONTH.format(fund.getCreateTime()));
        map.put("date", DateFormat.DAY.format(fund.getCreateTime()));

        map.put("amount", String.valueOf(fund.getAmount()));
        map.put("reason", String.valueOf(fund.getErrors()));
        sendLetterDTO.setMap(map);
        sendLetterDTO.setLetterCodeEnum(LetterCodeEnum.YXY_NOTICE_WITHDRAW_FAIL);
        mcenterRpcLetterService.send(sendLetterDTO);
    }

    private void sendMessage(FundAccountWithdrawPayment fund) {

        SendLetterDTO sendLetterDTO = new SendLetterDTO();
        sendLetterDTO.setPlatNo(fund.getPlatNo());
        sendLetterDTO.setUserBaseId(fundAccountMapper.selectByPrimaryKey(fund.getFundAccountId()).getUserBaseId());
        if (fund.getWithdrawType().equals(PayFromEnum.yxy_withdraw_mer.getCode())) {
            sendLetterDTO.setAppId(AppId.YXY_MER);
//        } else if (fund.getWithdrawType().equals(PayFromEnum.withdraw_mer.getCode())) {
//            sendLetterDTO.setAppId(AppId.KLKS_PRO);
        } else {
            if (PlatNoEnums.YXY.isEquals(fund.getPlatNo())) {
                sendLetterDTO.setAppId(AppId.YXY);
            } else {
                sendLetterDTO.setAppId(AppId.KLLC);
            }
        }
        Map<String, String> map = new HashMap<>();
        map.put("year", DateFormat.YEAR.format(fund.getCreateTime()));
        map.put("month", DateFormat.MONTH.format(fund.getCreateTime()));
        map.put("date", DateFormat.DAY.format(fund.getCreateTime()));

        map.put("amount", String.valueOf(fund.getAmount()));
        sendLetterDTO.setMap(map);
        sendLetterDTO.setLetterCodeEnum(LetterCodeEnum.YXY_NOTICE_WITHDRAW_SUCCESS);
        mcenterRpcLetterService.send(sendLetterDTO);
    }
}
